package com.masonluo.mlonlinejudge.service.impl;

import com.masonluo.mlonlinejudge.constant.RedisConstant;
import com.masonluo.mlonlinejudge.constant.TokenConstant;
import com.masonluo.mlonlinejudge.dao.*;
import com.masonluo.mlonlinejudge.entity.*;
import com.masonluo.mlonlinejudge.entity.Class;
import com.masonluo.mlonlinejudge.enums.Gender;
import com.masonluo.mlonlinejudge.enums.RolesEnum;
import com.masonluo.mlonlinejudge.enums.TokenType;
import com.masonluo.mlonlinejudge.exceptions.ResourceExistException;
import com.masonluo.mlonlinejudge.exceptions.ResourceNotFoundException;
import com.masonluo.mlonlinejudge.exceptions.UnknownException;
import com.masonluo.mlonlinejudge.mapper.UserInfoMapper;
import com.masonluo.mlonlinejudge.mapper.UserMapper;
import com.masonluo.mlonlinejudge.model.bo.SchoolBo;
import com.masonluo.mlonlinejudge.model.bo.UserBo;
import com.masonluo.mlonlinejudge.model.bo.UserInfoBo;
import com.masonluo.mlonlinejudge.model.bo.UserRankBo;
import com.masonluo.mlonlinejudge.model.cache.TokenCache;
import com.masonluo.mlonlinejudge.model.cache.TokenCacheMap;
import com.masonluo.mlonlinejudge.model.dto.*;
import com.masonluo.mlonlinejudge.model.param.StudentQueryParam;
import com.masonluo.mlonlinejudge.model.param.UserInfoQueryParam;
import com.masonluo.mlonlinejudge.service.TokenService;
import com.masonluo.mlonlinejudge.service.UserService;
import com.masonluo.mlonlinejudge.utils.CodecUtils;
import com.masonluo.mlonlinejudge.utils.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author masonluo
 * @date 2020/12/28 4:06 下午
 */
@Service
@DependsOn("redisTemplate")
public class UserServiceImpl implements UserService {

    public static final String PREFIX_USER = "user";

    public static final String PREFIX_NORMAL_TOKEN = "normal_token";

    public static final String PREFIX_REFRESH_TOKEN = "refresh_token";

    private final UserRepository userRepository;

    private final UserInfoRepository userInfoRepository;

    private final UserInfoMapper userInfoMapper;

    private final RedisTemplate<String, Object> redisTemplate;

    private final TokenService tokenService;

    @Resource
    RoleRepository roleRepository;

    @Resource
    UserRoleRepository userRoleRepository;

    @Resource
    UserMapper userMapper;

    @Resource
    ClassRepository classRepository;

    @Resource
    SchoolRepository schoolRepository;

    @Resource
    UserClassRepository userClassRepository;

    @Resource
    ExperimentResultRepository experimentResultRepository;

    public UserServiceImpl(UserRepository userRepository,
                           UserInfoRepository userInfoRepository,
                           UserInfoMapper userInfoMapper,
                           RedisTemplate<String, Object> redisTemplate,
                           TokenService tokenService) {
        this.userRepository = userRepository;
        this.userInfoRepository = userInfoRepository;
        this.userInfoMapper = userInfoMapper;
        this.redisTemplate = redisTemplate;
        this.tokenService = tokenService;
    }

    @Override
    public UserInfoDto register(String username, String password) {
        if (userRepository.countByUsername(username) > 0) {
            throw new ResourceExistException("The user [" + username + "] is already exist, please change another username");
        }
        // 加密后的密码
        String encryptPd = CodecUtils.md5DigestAsHex(password);
        User user = User.Builder.anUser()
                .withUsername(username)
                .withPassword(encryptPd)
                .build();
        userRepository.insert(user);
        if (user.getId() == null) {
            throw new UnknownException("There is a exception occur when insert user field");
        }
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNickname(user.getUsername());
        userInfo.setGender(Gender.UNKNOWN);
        userInfoRepository.insert(userInfo);
        return userInfoMapper.userInfoToUserInfoDto(user, userInfo);
    }

    /**
     * 进行用户登录，登录之后颁发一个Normal Token和一个Refresh Token
     * Normal Token用来进行用户的鉴权操作，判断用户是否已经登录
     * Refresh Token用来进行Normal Token的刷新，一般Refresh Token的过期时间会比Normal Token过期时间长
     * <p>
     * 在Redis里面保存着三个数据结构：
     * 1. String
     * key: user:{username}
     * value: {normal_token} （normal_token为String类型）
     * 这个结构用来获取当前用户的token，并且判断该是否已经过期
     * <p>
     * 2. Hash
     * key: normal_token:{normal_token}
     * -----------------------------
     * hash key: username
     * hash value: {username}
     * -----------------------------
     * hash key: normal_token
     * hash value: {normal_token} 类型: {@link com.masonluo.mlonlinejudge.model.cache.TokenCache}
     * -----------------------------
     * 过期时间： normal_token的expired_seconds
     * <p>
     * 3. Hash
     * key: refresh_token:{normal_token}
     * -----------------------------
     * hash key: username
     * hash value: {username}
     * -----------------------------
     * hash key: refresh_token
     * hash value: {refresh_token} 类型: {@link com.masonluo.mlonlinejudge.model.cache.TokenCache}
     * 过期时间: refresh_token的expired_seconds
     */
//    @Override
//    public LoginDto login(String username, String password) {
//        // 判断数据库是否有这个用户
//        User user = userRepository.selectByUsernameAndPassword(username, CodecUtils.md5DigestAsHex(password));
//        if (user == null) {
//            throw new IllegalArgumentException("username or password error, please input again");
//        }
//        String userToken = (String) redisTemplate.opsForValue()
//                .get(getRedisKeyForUser(username));
//        if (StringUtils.isBlank(userToken)) {
//            // 证明用户之前还没有登录，那么进行登录的操作
//            return doLogin(username);
//        }
//        if (ObjectUtils.nullSafeEquals(
//                redisTemplate.hasKey(getRedisKeyForNormalToken(userToken)), Boolean.TRUE)) {
//            // 证明token还存在，并未过期, 进行刷新操作
//            return doRefreshToken(username, userToken);
//        }
//        // 用户已经登录过，但是Token已经过期
//        clearLoginStatus(username, userToken);
//        // 重新登录
//        return doLogin(username);
//    }
    @Override
    public LoginInfoDto login(String username, String password, Integer schoolId) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
        } catch (AccountException accountException) {
            throw accountException;
        } catch (IncorrectCredentialsException incorrectCredentialsException) {
            throw incorrectCredentialsException;
        }
        return getLoginInfo(username, password, schoolId);
    }

    private LoginInfoDto getLoginInfo(String username, String password,Integer schoolId) {
        List<User> user = userRepository.selectByUsernameAndPassword(username, password);
        LoginInfoDto loginInfoDto = new LoginInfoDto();
        if (user!=null){
            for (User user1:user) {
                UserInfo userInfo = userInfoRepository.getUserInfoByUserId(user1.getId());
                if (schoolId.equals(userInfo.getSchoolId())) {
                    Role role = roleRepository.findByUserId(user1.getId());
                    String roleName = role.getName();
                    List<Class> classList = classRepository.selectClassListByUserId(userInfo.getUserId());
                    School school = schoolRepository.selectById(userInfo.getSchoolId());
                    loginInfoDto.setUserId(user1.getId());
                    loginInfoDto.setUsername(username);
                    loginInfoDto.setUserLevel(userInfo.getUserLevel());
                    loginInfoDto.setNickname(userInfo.getNickname());
                    loginInfoDto.setRoleName(roleName);
                    if (!CollectionUtils.isEmpty(classList)) {
                        loginInfoDto.setClassList(classList);
                    }
                    if (!Objects.isNull(school)) {
                        loginInfoDto.setSchoolId(school.getId());
                        loginInfoDto.setSchoolName(school.getSchoolName());
                        loginInfoDto.setSchoolBackground(school.getSchoolBackground());
                    }
                }
            }
        }
        if (loginInfoDto.getUserId()==null&&loginInfoDto.getUsername()==null){
            throw new IllegalArgumentException("拒绝访问");
        }
        return loginInfoDto;
    }

    /**
     * 进行登出操作
     */
    @Override
    public void logout(String username) {
        String token = getUserToken(username);
        if (!StringUtils.isBlank(token)) {
            clearLoginStatus(username, token);
        }
    }

    @Override
    public void renewalToken(String username, String token) {
        doRenewalToken(username, token);
    }

    @Override
    public boolean isLogin(String token) {
        return ObjectUtils.nullSafeEquals(Boolean.TRUE, redisTemplate.hasKey(getRedisKeyForNormalToken(token)));
    }

    @Override
    public Integer findIdByUsername(String username) {
        return userRepository.findIdByUsername(username);
    }

    @Override
    public String findUsernameById(Integer userId) {
        return userRepository.findUsernameById(userId);
    }

    @Override
    public String findUserSchoolById(Integer userId) {
        return userRepository.findUserSchoolById(userId);
    }

    @Override
    public Integer countById(Integer id) {
        return userRepository.countById(id);
    }

    /**
     * 真正进行登录的操作，将用户信息缓存到Redis里面，并且设置过期键
     */
    private LoginDto doLogin(String username) {
        String normalToken = tokenService.generateToken(username, TokenType.NORMAL);
        String refreshToken = tokenService.generateToken(username, TokenType.REFRESH);
        long timestamp = System.currentTimeMillis();
        // 分别记录两个Token的过期时间信息等
        TokenCache normalTokenCache =
                new TokenCache(normalToken, timestamp, TokenConstant.DEFAULT_NORMAL_TOKEN_EXPIRED_SECONDS, username);
        TokenCache refreshTokenCache =
                new TokenCache(refreshToken, timestamp, TokenConstant.DEFAULT_REFRESH_TOKEN_EXPIRED_SECONDS, username);
        // 缓存username对normal token的映射关系
        redisTemplate.opsForValue().set(getRedisKeyForUser(username), normalToken);
        // 缓存normal_token，及其设置过期时间
        TokenCacheMap nc = new TokenCacheMap();
        nc.setUsername(username);
        nc.setToken(normalTokenCache);
        nc.setTokenType(TokenType.NORMAL);
        redisTemplate.opsForHash().putAll(getRedisKeyForNormalToken(normalToken), nc);
        redisTemplate.expire(
                getRedisKeyForNormalToken(normalToken),
                TokenConstant.DEFAULT_NORMAL_TOKEN_EXPIRED_SECONDS,
                TimeUnit.SECONDS);
        // 缓存refresh_token，及其设置过期时间
        TokenCacheMap rc = new TokenCacheMap();
        rc.setUsername(username);
        rc.setToken(refreshTokenCache);
        rc.setTokenType(TokenType.REFRESH);
        redisTemplate.opsForHash().putAll(getRedisKeyForRefreshToken(normalToken), rc);
        redisTemplate.expire(
                getRedisKeyForRefreshToken(normalToken),
                TokenConstant.DEFAULT_REFRESH_TOKEN_EXPIRED_SECONDS,
                TimeUnit.SECONDS
        );

        TokenDto nDto =
                new TokenDto(normalToken, TokenType.NORMAL, timestamp, TokenConstant.DEFAULT_NORMAL_TOKEN_EXPIRED_SECONDS);
        TokenDto rDto =
                new TokenDto(refreshToken, TokenType.REFRESH, timestamp, TokenConstant.DEFAULT_REFRESH_TOKEN_EXPIRED_SECONDS);

        return new LoginDto(nDto, rDto, username);
    }

    /**
     * 进行刷新Token的过期时间，如果token不存在，那么重新进行登录
     */
    private LoginDto doRefreshToken(String username, String userToken) {
        // 如果两个Token都还没有过期
        if (ObjectUtils.nullSafeEquals(Boolean.TRUE, redisTemplate.hasKey(getRedisKeyForNormalToken(userToken)))
                && ObjectUtils.nullSafeEquals(Boolean.TRUE, redisTemplate.hasKey(getRedisKeyForRefreshToken(userToken)))) {
            return doRenewalToken(username, userToken);
        }
        // 如果过期了，重新登录，并且清除登录状态
        clearLoginStatus(username, userToken);
        return doLogin(username);
    }

    /**
     * 进行Token过期时间的延长操作，不进行判断该token是否还存在
     * 只进行刷新
     */
    private LoginDto doRenewalToken(String username, String userToken) {
        TokenCache nc, rc;
        TokenCacheMap ncm, rcm;

        ncm = new TokenCacheMap(
                redisTemplate.opsForHash().entries(getRedisKeyForNormalToken(userToken))
        );
        rcm = new TokenCacheMap(
                redisTemplate.opsForHash().entries(getRedisKeyForRefreshToken(userToken))
        );
        nc = ncm.getToken();
        rc = rcm.getToken();

        redisTemplate.expire(
                getRedisKeyForNormalToken(userToken), TokenConstant.DEFAULT_NORMAL_TOKEN_EXPIRED_SECONDS, TimeUnit.SECONDS);
        redisTemplate.expire(
                getRedisKeyForRefreshToken(userToken), TokenConstant.DEFAULT_REFRESH_TOKEN_EXPIRED_SECONDS, TimeUnit.SECONDS
        );
        TokenDto nDto, rDto;
        nDto = new TokenDto(
                nc.getToken(), ncm.getTokenType(), nc.getCreatedTimestamp(), nc.getExpiredSeconds());
        rDto = new TokenDto(
                rc.getToken(), rcm.getTokenType(), rc.getCreatedTimestamp(), rc.getExpiredSeconds());
        return new LoginDto(nDto, rDto, username);
    }

    /**
     * 获取缓存在Redis里面的 Token
     */
    private String getUserToken(String username) {
        return (String) redisTemplate.opsForValue().get(getRedisKeyForUser(username));
    }

    private void clearLoginStatus(String username) {
        clearLoginStatus(username,
                (String) redisTemplate.opsForValue().get(getRedisKeyForUser(username)));
    }

    private void clearLoginStatus(String username, String userToken) {
        redisTemplate.delete(getRedisKeyForUser(username));
        if (userToken != null) {
            redisTemplate.delete(getRedisKeyForNormalToken(userToken));
            redisTemplate.delete(getRedisKeyForRefreshToken(userToken));
        }
    }

    private String getRedisKeyForUser(String username) {
        return StringUtils.join(RedisConstant.SEPARATOR, PREFIX_USER, username);
    }

    private String getRedisKeyForNormalToken(String token) {
        return StringUtils.join(RedisConstant.SEPARATOR, PREFIX_NORMAL_TOKEN, token);
    }

    private String getRedisKeyForRefreshToken(String token) {
        return StringUtils.join(RedisConstant.SEPARATOR, PREFIX_REFRESH_TOKEN, token);
    }


    @Override
    public String getUserRolesByUsername(String username) {
        User user = userRepository.getUserByUsername(username);
        if (Objects.isNull(user)) {
            throw new ResourceNotFoundException("找不到对应的用户");
        }
        Role roles = roleRepository.findByUserId(user.getId());
        String roleName = roles.getName();
        return roleName;
    }

    @Override
    public String getUserRolesByUserId(Integer userId) {
        User user = userRepository.getUserByPrimaryKey(userId);
        if (Objects.isNull(user)) {
            throw new ResourceNotFoundException("找不到对应的用户");
        }
        Role role = roleRepository.findByUserId(user.getId());
        String roleName = role.getName();
        return roleName;
    }


    @Override
    public UserInfoDto getUserInfoByUserId(Integer userId) {
        User user = userRepository.getUserByPrimaryKey(userId);
        if (Objects.isNull(user)) {
            throw new ResourceNotFoundException("找不到对应的用户");
        }
        UserInfo userInfo = userInfoRepository.getUserInfoByUserId(userId);
        UserInfoDto userInfoDto = userInfoMapper.userInfoToUserInfoDto(user, userInfo);
        return userInfoDto;
    }

    @Override
    public UserInfoDto getUserInfoByIdOrName(String username, Integer userId) {
        User user = userRepository.getUserByIdOrName(userId, username);
        if (Objects.isNull(user)) {
            throw new ResourceNotFoundException("找不到对应的用户");
        }
        UserInfo userInfo = userInfoRepository.getUserInfoByUserId(userId);
        UserInfoDto userInfoDto = userInfoMapper.userInfoToUserInfoDto(user, userInfo);
        return userInfoDto;
    }


    @Override
    @Transactional
    public int addUserList(List<UserDto> userDtoList, List<String> nameDuplicate) {
            for (Iterator<UserDto> it = userDtoList.iterator(); it.hasNext(); ) {
                UserDto temp = it.next();
                for (int i=0;i<nameDuplicate.size();i++){
                    if (temp.getUsername().equals(nameDuplicate.get(i))){
                        it.remove();
                    }
                }
            }
        if (userDtoList.isEmpty())
            return -1;
        List<User> userList = userDtoList.stream().map(userDto -> {
            User user = new User();
            BeanUtils.copyProperties(userDto, user);
            user.setStatus(true);
            userRepository.insert(user);
            userDto.setUserId(user.getId());
            return user;
        }).collect(Collectors.toList());
        List<UserRole> userRoleList = userDtoList.stream().map(userDto -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(userDto.getUserId());
            userRole.setRoleId(RolesEnum.getRoleId(RolesEnum.getByName(userDto.getRole())));
            return userRole;
        }).collect(Collectors.toList());
        userRoleRepository.insertBatch(userRoleList);
        List<UserInfo> userInfoList = userDtoList.stream().map(userDto -> {
            return setUserInfo(userDto);
        }).collect(Collectors.toList());
        String role = getRole(userDtoList);
        int result = -1;
        if (RolesEnum.isStudent(role)) {
            List<UserClass> userClassList = getUserClassList(userDtoList);
            result = userInfoRepository.insertStudentInfoList(userInfoList);
            result = userClassRepository.insertBatch(userClassList);
        }
        if (RolesEnum.isTeacher(role)) {
            result = userInfoRepository.insertTeacherOrSchoolAdminInfo(userInfoList);
        }
        if (RolesEnum.isSchoolAdmin(role)) {
            result = userInfoRepository.insertTeacherOrSchoolAdminInfo(userInfoList);
        }
        if (RolesEnum.isSuperAdmin(role)) {
            result = userInfoRepository.insertSuperAdminInfo(userInfoList);
        }
        return result;
    }

    private String getRole(List<UserDto> userDtoList) {
        String role = null;
        for (UserDto userDto : userDtoList) {
            role = userDto.getRole();
            if (StringUtils.isNoneBlank(role)) {
                break;
            }
        }
        return role;
    }

    private UserInfo setUserInfo(UserDto userDto) {
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userDto, userInfo);
        userInfo.setUserId(userDto.getUserId());
        boolean userInfoIsEmpty = Objects.isNull(userInfo.getGender()) &&
                Objects.isNull(userInfo.getClassId()) &&
                Objects.isNull(userInfo.getSchoolId()) &&
                StringUtils.isBlank(userInfo.getNickname()) &&
                StringUtils.isBlank(userInfo.getPhone()) &&
                Objects.isNull(userInfo.getClassId()) &&
                Objects.isNull(userInfo.getSchoolId());
        if (userInfoIsEmpty) {
            userInfo.setUserId(userDto.getUserId());
            userInfo.setGender(Gender.UNKNOWN);
            userInfo.setNickname(" ");
            userInfo.setPhone(" ");
            userInfo.setClassId(0);
            userInfo.setSchoolId(0);
            return userInfo;
        }
//        t_user_class表存储用户班级关联关系
//            Integer classId=userInfo.getClassId();
//            UserClass userClass=new UserClass();
//            userClass.setUserId(userInfo.getUserId());
//            userClass.setClassId(classId);
//            userClassRepository.insertSelective(userClass);
        return userInfo;
    }

    private List<UserClass> getUserClassList(List<UserDto> userDtoList) {
        List<UserClass> userClassList = userDtoList.stream().map(userDto -> {
            UserClass userClass = new UserClass();
            userClass.setUserId(userDto.getUserId());
            userClass.setClassId(userDto.getClassId());
            return userClass;
        }).collect(Collectors.toList());
        return userClassList;
    }

    @Override
    public int deleteUserById(Integer userId) {
        return userRepository.deleteById(userId);
    }

    @Override
    @Transactional
    public int updateUserInfo(UserBo userBo) {
        int flag = -1;
        User user = userMapper.userBoToUser(userBo);
        boolean userNoChanged = StringUtils.isBlank(user.getUsername()) && StringUtils.isBlank(user.getPassword());
        if (!userNoChanged) {
            flag = userRepository.updateByPrimaryKey(user);
        }
        UserInfo userInfo = userInfoMapper.userBoToUserInfo(userBo);
        boolean userInfoNoChanged = (StringUtils.isBlank(userInfo.getNickname()) || Objects.equals(userInfo.getNickname(), "null")) &&
                (StringUtils.isBlank(userInfo.getPhone()) || Objects.equals(userInfo.getPhone(), "null")) &&
                Objects.isNull(userInfo.getGender()) && Objects.isNull(userInfo.getSchoolId());
        if (!userInfoNoChanged) {
            String newNickname = userInfoRepository.getUserInfoByUserId(userBo.getUserId()).getNickname();
            if (!newNickname.equals(userBo.getNickname())){

                //修改了昵称则要同步修改实验成绩表的用户名
                experimentResultRepository.updateUserNameByUserId(userBo.getUserId(),userBo.getNickname());
            }
            flag = userInfoRepository.updateByUserId(userInfo);

        }
        UserClass userClass = userInfoMapper.userBoToUserClass(userBo);
        boolean classNoChanged = Objects.isNull(userClass.getClassId());
        if (!classNoChanged) {
            userClassRepository.updateByUserId(userClass);
        }
        return flag;
    }

    @Override
    public List<UserInfoDto> queryPageUserInfoByRole(UserInfoQueryParam param) {
        Integer roleId = RolesEnum.getRoleId(RolesEnum.getByName(param.getRole()));
        List<UserInfoBo> userInfoBoList = userInfoRepository.queryPageUserInfoByRole(roleId, param.getPageNum(), param.getPageSize());
        userInfoBoList.forEach(userInfoBo -> {
            if (Strings.isBlank(userInfoBo.getGender())) {
                userInfoBo.setGender(Gender.UNKNOWN.name());
            } else {
                Gender gender = Gender.getById(Integer.parseInt(userInfoBo.getGender()));
                userInfoBo.setGender(gender.name());
            }
        });
        List<UserInfoDto> userInfoDtoList = userInfoMapper.to(userInfoBoList);
        return userInfoDtoList;
    }

    @Override
    public Integer getTotalByRole(Integer roleId) {
        Integer total = userRoleRepository.getTotalByRole(roleId);
        return total;
    }

    @Override
    public List<UserInfoDto> queryPageUserInfoByNickOrName(UserInfoQueryParam param) {
        Integer roleId = RolesEnum.getRoleId(RolesEnum.getByName(param.getRole()));
        List<Integer> userIdList = userRepository.queryUserIdListByNickOrName(param.getSchoolId(), param.getUsernameKey(), param.getNicknameKey(),roleId);
        List<UserInfoBo> userInfoBoList = userInfoRepository.queryPageUserInfoByUserIdList(userIdList, param.getPageNum(), param.getPageSize());
        List<UserInfoDto> userInfoDtoList = userInfoMapper.to(userInfoBoList);
        return userInfoDtoList;
    }

    @Override
    public Integer getTotalByNickOrNameKey(Integer schoolId, String username,String nickname, String role) {
        int roleId = RolesEnum.getByName(role).getRoleId();
        return userRepository.getTotalByNickOrNameKey(schoolId,username,nickname,roleId);
    }

    @Override
    public boolean checkUserSchoolExist(List<UserDto> userDtoList) {
        List<Integer> schoolIdList = userDtoList.stream()
                .filter(userDto -> !Objects.isNull(userDto.getSchoolId()))
                .map(userDto -> {
                    return userDto.getSchoolId();
                })
                .collect(Collectors.toList());
        String role = getRole(userDtoList);
        boolean roleIsSuperAdmin = RolesEnum.isSuperAdmin(role);
        if (CollectionUtils.isEmpty(schoolIdList) || schoolIdList.size() == 0) {
            if (roleIsSuperAdmin) {
                return true;
            }
            return false;
        }
        List<Integer> result = schoolRepository.selectByPrimaryKey(schoolIdList);
        boolean resultListIsEmpty = CollectionUtils.isEmpty(result) || result.size() == 0;
        if (resultListIsEmpty) {
            return false;
        }
        return true;
    }

    @Override
    public boolean checkUserClassExist(List<UserDto> userDtoList) {
        List<Integer> classIdList = userDtoList.stream()
                .filter(userDto -> !Objects.isNull(userDto.getClassId()))
                .map(userDto -> {
                    return userDto.getClassId();
                })
                .collect(Collectors.toList());
        String role = getRole(userDtoList);
        boolean roleIsTeacherOrSchoolAdmin = RolesEnum.isTeacher(role) || RolesEnum.isSchoolAdmin(role) || RolesEnum.isSuperAdmin(role);
        if (CollectionUtils.isEmpty(classIdList) || classIdList.size() == 0) {
            if (roleIsTeacherOrSchoolAdmin) {
                return true;
            }
            return false;
        }
        List<Integer> result = classRepository.selectByPrimaryKeyList(classIdList);
        boolean resultListIsEmpty = CollectionUtils.isEmpty(result) || result.size() == 0;
        if (resultListIsEmpty) {
            return false;
        }
        return true;
    }

    @Override
    public List<String> checkUserNameDuplicate(List<UserDto> userDtoList) {
        //获取用户名
        List<String> usernameList = userDtoList.stream().map(userDto -> {
            return userDto.getUsername();
        }).collect(Collectors.toList());
        List<String> result = userRepository.selectByUsername(usernameList);
//        boolean resultListIsEmpty = CollectionUtils.isEmpty(result) || result.size() == 0;
//        if (!resultListIsEmpty) {
//            return result;
//        }
        return result;
    }

    @Override
    public List<UserInfoDto> queryPageUserBoBySchoolId(Integer schoolId, String roleName, Integer pageNum, Integer pageSize) {
        SchoolBo schoolBo = schoolRepository.findSchoolById(schoolId);
        if (Objects.isNull(schoolBo)) {
            throw new IllegalArgumentException("学校不存在");
        }
        Integer roleId = RolesEnum.getByName(roleName).getRoleId();
        List<UserInfoBo> userInfoBoList = userInfoRepository.queryUserBoBySchool(schoolId, roleId, pageNum, pageSize);
        List<UserInfoDto> userInfoDtoList = userInfoMapper.to(userInfoBoList);
        return userInfoDtoList;
    }

    @Override
    public Integer getTotalBySchoolId(Integer schoolId, String roleName) {
        Integer roleId = RolesEnum.getByName(roleName).getRoleId();
        Integer total = userInfoRepository.getTotalBySchoolId(schoolId, roleId);
        return total;
    }

    @Override
    public void updateUserLevel(Integer userId) {
        userInfoRepository.updateUserLevel(userId);
    }


    @Override
    public List<UserRankBo> queryPageRankBySchoolId(Integer schoolId, Integer pageNum, Integer pageSize) {
        SchoolBo schoolBo = schoolRepository.findSchoolById(schoolId);
        if (Objects.isNull(schoolBo)) {
            throw new IllegalArgumentException("学校不存在");
        }
        List<UserRankBo> userRankList = userInfoRepository.queryPageRankBySchoolId(schoolId, pageNum, pageSize);
        return userRankList;
    }

    @Override
    public List<UserInfoDto> getInfoByClassIdAndUsernameOrNickname(StudentQueryParam param) {
        List<Integer> userIdList = userRepository.getUserIdListByUsernameOrnickName(param.getClassId(), param.getUsernameKey(),param.getNicknameKey());
        List<UserInfoBo> userInfoBoList = userInfoRepository.queryPageUserInfoByUserIdList(userIdList, param.getPageNum(),param.getPageSize());
        List<UserInfoDto> userInfoDtoList = userInfoMapper.to(userInfoBoList);
        return userInfoDtoList;
    }

    @Override
    public Integer getTotalByClassIdAndUserNameOrNickName(Integer classId, String usernameKey,String nickNameKey) {
        return userInfoRepository.getTotalByClassIdAndUserOrNick(classId, usernameKey,nickNameKey);
    }
}
